// const { includes, xor } = require("lodash")


const a = 'padding'
const b = 'ok'
const c = 'on'

/*
// 只考虑 new Promise的时候是同步代码 并且不能连续.then().then()
class MyPromise {
    constructor(fn){
        fn(this.ok,this.on)
    }
    // promise成功或者失败的结果
    res = null
    error = null
    // 状态
    status = 'padding'
    ok = (res) => {
        if(this.status !== 'padding') return;
        this.status = 'ok'
        this.res = res
  
    }
    on = (error) => {
        if(this.status !== 'padding') return;
        this.status = 'on'
        this.error = error
    }
    then = (ok,on) => {
        if(this.status === 'ok'){
            ok(this.res)
        }else if(this.status === 'on'){
            on(this.error)
        }

    }
}
const my = new MyPromise((ok,on)=>{
    ok('ok')
})
my.then(res =>{
    console.log(res,3);
})
*/



/*
// 开始考虑new promsie的时候 可以传入异步代码
// 在类中设置一个变量存储传入 ok  on  当异步结束执行对应的成功或者失败时，也一起执行存储ok  或者 on
class MyPromise {
    constructor(fn){
        fn(this.ok,this.on)
    }
    res = null
    error = null
    status = 'padding'
    ok1 = undefined
    on1 = undefined
    ok = (res) => {
        if(this.status !== 'padding') return;
        this.status = 'ok'
        this.res = res
        // 如果是异步的情况，那就等异步完成后调用成功函数
        this.ok && this.ok(res)

    }
    on = (error) => {
        if(this.status !== 'padding') return;
        this.status = 'on'
        this.error = error
        // 异步情况
        this.on && this.on(error)
    }
    then = (ok,on) => {
        if(this.status === 'ok'){
            ok(this.res)
        }else if(this.status === 'on'){
            on (this.error)
        // 异步情况，将ok on 保存下来，等待异步结束调用 
        }else{
            this.ok1 = ok
            this.on1 = on
        }

    }
}
const my = new MyPromise((ok,on)=>{
    setTimeout(() => {
        ok('ok')
    }, 1000);
    
})
my.then(res =>{
    console.log(res,3);
})
*/


/*
// 开始考虑 当new promise是异步代码时， 同一个promsie可以被多次.then的情况
// 因为同一个promise 多次.then 还是异步的时候，类里面保存的ok on会被覆盖
// 采用了数组的方式，将ok on 放入一个数组中，每次状态改变 时，执行所有的 ok on
class MyPromise {
    constructor(fn){
        fn(this.ok,this.on)
    }
    res = null
    error = null
    status = 'padding'
    ok1 = []
    on1= []
    ok = (res) => {
        if(this.status !== 'padding') return;
        this.status = 'ok'
        this.res = res
        // 多次.then()
        while (this.ok.length) {
            this.ok.shift()(res)
        }

    }
    on = (error) => {
        if(this.status !== 'padding') return;
        this.status = 'on'
        this.error = error
        while (this.on.length) {
            this.on.shift()(res)
        }
    }
    then = (ok,on) => {
        if(this.status === 'ok'){
            ok(this.res)
        }else if(this.status === 'on'){
            on2(this.error)
        }else{
            this.ok1.push(ok)
            this.on1.push(on)
        }

    }
}
const my = new MyPromise((ok,on)=>{
    setTimeout(() => {
        ok('ok')
    }, 1000);
    
})
my.then(res =>{
    console.log(res,3);
})
my.then(res =>{
    console.log(res,4);
})
my.then(res =>{
    console.log(res,5);
})
*/


// 开始考虑可以连续.then().then()的情况 但是在.then()中只能返回原始值，不能是promise
// 要实现连续.then().then() .then中return 的必须是一个promsie 
// class MyPromise {
//     constructor(fn){
//         fn(this.ok,this.on)
//     }
//     res = null
//     error = null
//     status = 'padding'
//     ok1 = []
//     on1 = []
//     ok = (res) => {
//         if(this.status !== 'padding') return;
//         this.status = 'ok'
//         this.res = res
//         while (this.ok1.length) {
//             this.ok1.shift()(res)
//         }

//     }
//     on = (error) => {
//         if(this.status !== 'padding') return;
//         this.status = 'on'
//         this.error = error
//         while (this.on1.length) {
//             this.on1.shift()(res)
//         }
//     }
//     then = (ok1,on1) => {
//         // .then().then() 可以链式调用
//         let promise2 = new MyPromise((ok2,on2) => {
//             if(this.status === 'ok'){
//                 let x = ok1(this.res) 
//                 ok2(x)
//             }else if(this.status === 'on'){
//                 on1(this.error)
                
//             }else{
//                 this.ok1.push(ok1)
//                 this.on1.push(on1)
//             }
//         })
//         return promise2

//     }
// }
// const my = new MyPromise((ok,on)=>{
//     setTimeout(() => {
//         ok('ok')
//     }, 1000);
//     /**
//      * 目前只能是同步
//      * 因为my.then()的执行在延迟计时器之前，会执行this.ok1.push(ok1)，一秒后执行ok()就完事了，
//      * promise2的ok2和on2，只在ok中确定了状态，由于在其他条件中promise2没有确定状态所以第二个.then也不会执行
//      */
//     // ok('ok')
// })
// my.then(res =>{
//     console.log(res); // ok
//     return 100
// }).then(res => {
//     console.log(res); // 100
// })


// 当.then()中返回的promise的情况
// 并且利用queueMicrotask来避免.then中返回promise2,，造成自身循环调用的情况
// class MyPromise {
//     constructor(fn){
//         fn(this.ok,this.on)
//     }
//     res = null
//     error = null
//     status = 'padding'
//     ok1 = []
//     on1 = []
//     ok = (res) => {
//         if(this.status !== 'padding') return;
//         this.status = 'ok'
//         this.res = res
//         while (this.ok1.length) {
//             this.ok1.shift()(res)
//         }

//     }
//     on = (error) => {
//         if(this.status !== 'padding') return;
//         this.status = 'on'
//         this.error = error
//         while (this.on1.length) {
//             this.on1.shift()(res)
//         }
//     }
//     then = (ok1,on1) => {
//         // .then().then() 可以链式调用
//         let promise2 = new MyPromise((ok2,on2) => {
//             if(this.status === 'ok'){
//                 // 使用queueMicrotask的原因是因为要避免.then中返回promise2, 造成自身循环调用
//                 // 因为promise2中执行的是同步代码，所以promise2还没有值，所以用一个异步来获取promise2
//                 queueMicrotask(() => {
//                     let x = ok1(this.res)
//                     // 判断 x 的值是普通值还是promise对象
//                     // 如果是普通值 直接调用resolve 
//                     // 如果是promise对象 查看promsie对象返回的结果 
//                     // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
//                     resolvePromise(promise2,x, ok2, on2)
//                 })
                
//             }else if(this.status === 'on'){
//                 on1(this.error)
                
//             }else{
//                 this.ok1.push(ok1)
//                 this.on1.push(on1)
//             }
//         })
//         return promise2

//     }
// }
// function  resolvePromise(promise2,x, resolve, reject) {
//     // x的值不能是promise2，会出现循环调用，例子看test.html
//     if (promise2 === x) {
//         return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
//       }
//     if(x instanceof  MyPromise){
//         // promise

//         // 将x的promise的状态传递给promise2
//         // x.then(value => resolve(value), reason => reject(reason));
//         // 简写
//         x.then(resolve,reject)

//     }else{
//         // 原始值
//         resolve(x)
//     }
// }
// const my = new MyPromise((ok,on)=>{
//     ok('ok')
// })

// function other(){
//     return new MyPromise((res,rej) => {
//         console.log('同步other');
//         res('other')
//     })
// }
// my.then(res =>{
//     console.log(res); // ok
//     return other();
// }).then(res => {
//     console.log(res); // other
// })








/*
        1.捕获错误以及then链式调用其他状态码补充，增加try catch

        2.补充对catch 和 异步情况的代码，因为之前一直都是在对then做处理，
                catch和then一样，
                异步的情况：push的时候改成一个函数，然后将代码复制进去，并且取消在ok和on中while循环的参数传递，因为在push的函数中已经传入了

        3.实现then方法的参数可选，就是.then().then().then(res => {})，其中两个then没有传参，第三个then传参
                    参数可选，如果用户没有传参数，那就用默认的参数
*/ 
// class MyPromise {
//     constructor(fn){
//         try {
//             fn(this.ok,this.on)
//         }catch(e){
//             this.on(e)
//         }
        
//     }
//     res = null
//     error = null
//     status = 'padding'
//     ok1 = []
//     on1 = []
//     ok = (res) => {
//         if(this.status !== 'padding') return;
//         this.status = 'ok'
//         this.res = res
//         while (this.ok1.length) {
//             this.ok1.shift()()
//         }

//     }
//     on = (error) => {
//         if(this.status !== 'padding') return;
//         this.status = 'on'
//         this.error = error
//         while (this.on1.length) {
//             this.on1.shift()()
//         }
//     }
//     then = (ok1,on1) => {
//         // 参数可选
//         ok1 = ok1 ? ok1 : value => value;
//         // 参数可选
//         on1 = on1 ? on1: reason => { throw reason };


//         // .then().then() 可以链式调用
//         let promise2 = new MyPromise((ok2,on2) => {
//             if(this.status === 'ok'){
                
//                 // 使用queueMicrotask的原因是因为要避免.then中返回promise2, 造成自身循环调用
//                 // 因为promise2中执行的是同步代码，所以promise2还没有值，所以用一个异步来获取promise2
//                 queueMicrotask(() => {
//                     try{
//                         let x = ok1(this.res)
//                         // 判断 x 的值是普通值还是promise对象
//                         // 如果是普通值 直接调用resolve 
//                         // 如果是promise对象 查看promsie对象返回的结果 
//                         // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
//                         resolvePromise(promise2,x, ok2, on2)
//                     }catch(e){
//                         on2(e)
//                     }
                    
//                 })
                
//             }else if(this.status === 'on'){
                
//                 queueMicrotask(() => {
//                     try{
//                         let x = on1(this.error)
//                         resolvePromise(promise2,x, ok2, on2)
//                     }catch(e){
//                         on2(e)
//                     }
                    
//                 })
                
//             }else{
//                 this.ok1.push(() => {
//                     queueMicrotask(() => {
//                         try{
//                             let x = ok1(this.res)
//                             resolvePromise(promise2,x, ok2, on2)
//                         }catch(e){
//                             on2(e)
//                         }
                        
//                     })
//                 })
//                 this.on1.push(() => {
//                     queueMicrotask(() => {
//                         try{
//                             let x = on1(this.error)
//                             resolvePromise(promise2,x, ok2, on2)
//                         }catch(e){
//                             on2(e)
//                         }
                        
//                     })
//                 })
//             }
//         })
//         return promise2

//     }
// }
// function  resolvePromise(promise2,x, resolve, reject) {
//     // x的值不能是promise2，会出现循环调用，例子看test.html
//     if (promise2 === x) {
//         return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
//       }
//     if(x instanceof  MyPromise){
//         // promise

//         // 将x的promise的状态传递给promise2
//         // x.then(value => resolve(value), reason => reject(reason));
//         // 简写
//         x.then(resolve,reject)

//     }else{
//         // 原始值
//         resolve(x)
//     }
// }
// const my = new MyPromise((ok,on)=>{
//     // ok('ok')
//     // throw new Error('报错')

// })

// function other(){
//     return new MyPromise((res,rej) => {
//         console.log('同步other');
//         res('other')
//     })
// }
// my.then().then().then(res =>{
//     console.log(res); // ok
//     return other();
// },err => {
//     console.log(err);
// }).then(res => {
//     console.log(res); // other
// },err => {
//     console.log(err);
// })





/*
    实现promsie 的一些方法

    promise.all：all中可能有异步的情况，所以用index来确定所有的异步都能完成
    promise.resolve：如果promise就完整返回，如果是原始值就用promise包装
    finally：无论成功还是失败都执行finally，并且在finally中return异步函数，finally之后的then也会等待异步函数执行完毕在执行后面的then
    catch:可以实现.then().catch()调用，通过内部的this.then()来实现

*/

class MyPromise {
    constructor(fn){
        try {
            fn(this.ok,this.on)
        }catch(e){
            this.on(e)
        }
        
    }
    res = null
    error = null
    status = 'padding'
    ok1 = []
    on1 = []
    ok = (res) => {
        if(res instanceof MyPromise){
            // 递归解析值
            // 看下面例子
            return value.then(this.ok,this.on)
          }
        if(this.status !== 'padding') return;
        this.status = 'ok'
        this.res = res
        while (this.ok1.length) {
            this.ok1.shift()()
        }

    }
    on = (error) => {
        if(this.status !== 'padding') return;
        this.status = 'on'
        this.error = error
        while (this.on1.length) {
            this.on1.shift()()
        }
    }
    catch (failCallback) {
        return this.then(undefined, failCallback)
    }
    then = (ok1,on1) => {
        // 参数可选
        ok1 = ok1 ? ok1 : value => value;
        // 如果传入的不是函数，值透传
        // ok1 = typeof ok1 === 'function' ? ok1 : value => value;

        // 参数可选
        on1 = on1 ? on1: reason => { throw reason };


        // .then().then() 可以链式调用
        let promise2 = new MyPromise((ok2,on2) => {
            if(this.status === 'ok'){
                // 因为promise2中执行的是同步代码，在resolvePromise传参中promise2还没有值，所以用queueMicrotask异步来获取promise2
                queueMicrotask(() => {
                    try{
                        let x = ok1(this.res)
                        // 判断 x 的值是普通值还是promise对象
                        // 如果是普通值 直接调用resolve 
                        // 如果是promise对象 查看promsie对象返回的结果 
                        // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
                        resolvePromise(promise2,x, ok2, on2)
                    }catch(e){
                        on2(e)
                    }
                    
                })
                
            }else if(this.status === 'on'){
                
                queueMicrotask(() => {
                    try{
                        let x = on1(this.error)
                        resolvePromise(promise2,x, ok2, on2)
                    }catch(e){
                        on2(e)
                    }
                    
                })
                
            }else{
                this.ok1.push(() => {
                    queueMicrotask(() => {
                        try{
                            let x = ok1(this.res)
                            resolvePromise(promise2,x, ok2, on2)
                        }catch(e){
                            on2(e)
                        }
                        
                    })
                })
                this.on1.push(() => {
                    queueMicrotask(() => {
                        try{
                            let x = on1(this.error)
                            resolvePromise(promise2,x, ok2, on2)
                        }catch(e){
                            on2(e)
                        }
                        
                    })
                })
            }
        })
        return promise2

    }

    static all(array){
        let result = [];
        let index = 0;
        return new MyPromise((resolve, reject) => {
            function addData (key, value) {
                result[key] = value;
                index++;
                if (index === array.length) {
                    resolve(result);
                }
            }
            for (let i = 0; i < array.length; i++) {
                let current = array[i];
                MyPromise.resolve(current).then(res => {
                    addData(i,res);
                    // 监听数组项中的Promise catch只要有一个失败，那么我们自己返回的Promise也会失败
                  }).catch(reject)


                // let current = array[i];
                // if (current instanceof MyPromise) {
                //     // promise 对象,如果有一个失败，那整体就是失败
                //     current.then(value => addData(i, value), reason =>  (reason))
                // }else {
                //     // 普通值
                //     addData(i, array[i]);
                // }
            }
            // 会有问题，for循环是瞬间执行完毕，array中可能有异步，result中可能会有异步没执行完毕，就resolve，所以直接result是有问题的
            // 解决方法 index
            // resolve(result)

         })
    }

    static resolve (value) {
        // 在MyPromise的resolve中进行处理
        return new MyPromise((resolve,reject)=>{
            resolve(value)
        })
    }
    // 无论成功还是失败都会执行一次callback，成功和失败的状态在this.then中都有，所以finally用then来实现
    finally (callback) {
        return this.then(value => {
            // return也用promise包裹是因为 在 finall中也可能 return 异步 ，所以要用resolve()包裹 
          return MyPromise.resolve(callback()).then(() => value);
        }, reason => {
          return MyPromise.resolve(callback()).then(() => { throw reason })
        })
    }
}
function  resolvePromise(promise2,x, resolve, reject) {
    // x的值不能是promise2，会出现循环调用，例子看test.html
    if (promise2 === x) {
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
      }
    if(x instanceof  MyPromise){
        // promise

        // 将x的promise的状态传递给promise2
        // x.then(value => resolve(value), reason => reject(reason));
        // 简写
        x.then(resolve,reject)

    }else{
        // 原始值
        resolve(x)
    }
}
// function p1(){
//     return new MyPromise((res,rej) => {
//         setTimeout(() => {
//             res('p1')
//         },0)
//     })
// }
// function p2(){
//     return new MyPromise((res,rej) => {
//         res('p2')
//     })
// }
// MyPromise.all(['a','b',p1(),p2(),'c']).then(res => {
//     // 返回值的顺序也和 all中的顺序一样，哪怕p2 比 p1 快
//     // res -> ['a','b',p1,p2,'c']
//     console.log(res);
// })
